#ifndef __fbmem_bmp_deconfig__h__
#define __fbmem_bmp_deconfig__h__

#define BMP_SERIVE_ADDR 0x81E00000

struct bmp_info
{
    uint16_t bmp_mark;
    uint32_t bmp_size;
    uint32_t aside;
    uint32_t data_offset;
    uint32_t info_size;
    uint32_t width;
    uint32_t height;
    uint16_t Planes;
    uint16_t bpp;
    uint32_t tar_mode;
    uint32_t image_byte;
    uint32_t level;
    uint32_t vertical;
    uint32_t bit;
};

/*原始BMP图片数据*/
static uint8_t *file_bmp_data;
static uint8_t *image_info_address;

/*解码后的数据*/
static uint8_t *decode_data = NULL;

static int Sorting_change(uint8_t *bmp, uint32_t width, uint32_t height, uint16_t bmp_numbyte)
{
    int x, y;
    uint32_t *bit32_p = NULL, *bit32_bmp = NULL;
    uint8_t *false_bit24_p = NULL, *false_bit24_bmp = NULL;
    uint32_t p_addr,bmp_addr;
    uint16_t *bit16_p = NULL, *bit16_bmp = NULL;
    uint8_t *bit8_p = NULL, *bit8_bmp = NULL;

    // uint8_t r,g,b;
    decode_data = kmalloc(width * height * bmp_numbyte, GFP_KERNEL);
    if (decode_data == NULL)
    {
        printk(KERN_WARNING "LOGO mem bit24_bmp_decode failed\n");
        return 1;
    }

    /*
    *MBP数据是从左下角往右上角存储的
    *FB是从坐上脚往右下角刷新的
    *需要把BMP数据转换成FB数据，不然LOGO就是上下颠倒的
    *所有的格式理论都可以用类似3Byte（24Bit）的处理方式，这样能减小内存的消耗，但是处理速度会相应的变慢
    */
    if (bmp_numbyte == 1)
    {
        bit8_p = (uint8_t *)decode_data;
        bit8_bmp = (uint8_t *)bmp;
    }
    else if (bmp_numbyte == 2)
    {
        bit16_p = (uint16_t *)decode_data;
        bit16_bmp = (uint16_t *)bmp;
    }
    else if (bmp_numbyte == 3)
    {
        false_bit24_p = (uint8_t *)decode_data;
        false_bit24_bmp = (uint8_t *)bmp;
    }
    else if (bmp_numbyte == 4)
    {
        bit32_p = (uint32_t *)decode_data;
        bit32_bmp = (uint32_t *)bmp;
    }

    switch (bmp_numbyte)
    {
    case 1:
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                bit8_p[(y * width) + x] = bit8_bmp[((width * height) - ((y + 1) * width)) + x];
            }
        }
        break;
    case 2:
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                bit16_p[(y * width) + x] = bit16_bmp[((width * height) - ((y + 1) * width)) + x];
            }
        }
        break;
    case 3:
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                p_addr = ((y * (width * bmp_numbyte)) + (x * bmp_numbyte));
                bmp_addr = (width * height * bmp_numbyte) - (((y + 1) * width * bmp_numbyte)) + (x * bmp_numbyte);
                false_bit24_p[p_addr] = false_bit24_bmp[bmp_addr];
                false_bit24_p[p_addr+1] = false_bit24_bmp[bmp_addr+1];
                false_bit24_p[p_addr+2] = false_bit24_bmp[bmp_addr+2];
            }
        }
        break;
    case 4:
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                bit32_p[(y * width) + x] = bit32_bmp[((width * height) - ((y + 1) * width)) + x];
            }
        }
        break;
    default:
        return 1;
    }
    return 0;
}

int bmp_decode(uint32_t *width, uint32_t *height, uint8_t *bpp, uint8_t **data)
{
    // int i;
    // static uint8_t *addr;
    static struct bmp_info bmp_image_info;

    /*将物理地址映射为虚拟地址*/
    image_info_address = ioremap_nocache(BMP_SERIVE_ADDR, sizeof(struct bmp_info));
    if (image_info_address == NULL)
    {
        printk(KERN_WARNING "LOGO mem application failed\n");
        return 1;
    }

    /*开始使用的地址映射，发现数据不对，因该是16位和32位地址对其问题*/
    bmp_image_info.bmp_mark = readw(image_info_address);
    image_info_address += 2;
    bmp_image_info.bmp_size = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.aside = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.data_offset = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.info_size = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.width = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.height = readl(image_info_address);
    image_info_address += 4;
    bmp_image_info.Planes = readl(image_info_address);
    image_info_address += 2;
    bmp_image_info.bpp = readl(image_info_address);
    image_info_address += 2;
    bmp_image_info.tar_mode = readl(image_info_address);

    printk(KERN_INFO "BMP file size is %d\n", bmp_image_info.bmp_size);
    printk(KERN_INFO "BMP bpp is %d\n", bmp_image_info.bpp);
    printk(KERN_INFO "BMP data offset is %d\n", bmp_image_info.data_offset);
    printk(KERN_INFO "BMP tar_mode is %d\n", bmp_image_info.tar_mode);

    /*文件合法性判断*/
    if (bmp_image_info.bmp_mark != 0x4D42)
    {
        printk(KERN_WARNING "Logo file is not BMP,%x\n", bmp_image_info.bmp_mark);
        return 1;
    }
    if (bmp_image_info.tar_mode != 0)
    {
        printk(KERN_WARNING "You need to use an uncompressed BMP file,%x\n", bmp_image_info.tar_mode);
        return 1;
    }
    if ((bmp_image_info.bpp != 8) && (bmp_image_info.bpp != 16) && (bmp_image_info.bpp != 24) && (bmp_image_info.bpp != 32))
    {
        printk(KERN_WARNING "Logo file bpp error,%x\n", bmp_image_info.bpp);
        return 1;
    }

    /*取出像素数据*/
    file_bmp_data = ioremap_nocache((BMP_SERIVE_ADDR + bmp_image_info.data_offset), (bmp_image_info.width * bmp_image_info.height) * (bmp_image_info.bpp / 8));
    if (file_bmp_data == NULL)
    {
        printk(KERN_WARNING "LOGO file_bmp_data mem application failed\n");
        return 1;
    }

    if (Sorting_change(file_bmp_data, bmp_image_info.width, bmp_image_info.height, (bmp_image_info.bpp / 8)))
        return 1;

    *bpp = bmp_image_info.bpp;
    *width = bmp_image_info.width;
    *height = bmp_image_info.height;
    *data = decode_data;

    return 0;
}

void ioremap_del(void)
{
    kfree(decode_data);
    iounmap(image_info_address);
    iounmap(file_bmp_data);
}

#endif
